/**
 *******************************************************************************
 * @file  basic.c
 * @brief This file provides firmware functions to manage the basic driver.
 @verbatim
   Change Logs:
   Date             Author          Notes
   2019-06-26       Yangjp          First version
 @endverbatim
 *******************************************************************************
 * Copyright (C) 2016, Huada Semiconductor Co., Ltd. All rights reserved.
 *
 * This software is owned and published by:
 * Huada Semiconductor Co., Ltd. ("HDSC").
 *
 * BY DOWNLOADING, INSTALLING OR USING THIS SOFTWARE, YOU AGREE TO BE BOUND
 * BY ALL THE TERMS AND CONDITIONS OF THIS AGREEMENT.
 *
 * This software contains source code for use with HDSC
 * components. This software is licensed by HDSC to be adapted only
 * for use in systems utilizing HDSC components. HDSC shall not be
 * responsible for misuse or illegal use of this software for devices not
 * supported herein. HDSC is providing this software "AS IS" and will
 * not be responsible for issues arising from incorrect user implementation
 * of the software.
 *
 * Disclaimer:
 * HDSC MAKES NO WARRANTY, EXPRESS OR IMPLIED, ARISING BY LAW OR OTHERWISE,
 * REGARDING THE SOFTWARE (INCLUDING ANY ACCOMPANYING WRITTEN MATERIALS),
 * ITS PERFORMANCE OR SUITABILITY FOR YOUR INTENDED USE, INCLUDING,
 * WITHOUT LIMITATION, THE IMPLIED WARRANTY OF MERCHANTABILITY, THE IMPLIED
 * WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE OR USE, AND THE IMPLIED
 * WARRANTY OF NONINFRINGEMENT.
 * HDSC SHALL HAVE NO LIABILITY (WHETHER IN CONTRACT, WARRANTY, TORT,
 * NEGLIGENCE OR OTHERWISE) FOR ANY DAMAGES WHATSOEVER (INCLUDING, WITHOUT
 * LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS, BUSINESS INTERRUPTION,
 * LOSS OF BUSINESS INFORMATION, OR OTHER PECUNIARY LOSS) ARISING FROM USE OR
 * INABILITY TO USE THE SOFTWARE, INCLUDING, WITHOUT LIMITATION, ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL OR CONSEQUENTIAL DAMAGES OR LOSS OF DATA,
 * SAVINGS OR PROFITS,
 * EVEN IF Disclaimer HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
 * YOU ASSUME ALL RESPONSIBILITIES FOR SELECTION OF THE SOFTWARE TO ACHIEVE YOUR
 * INTENDED RESULTS, AND FOR THE INSTALLATION OF, USE OF, AND RESULTS OBTAINED
 * FROM, THE SOFTWARE.
 *
 * This software may be replicated in part or whole for the licensed use,
 * with the restriction that this Disclaimer and Copyright notice must be
 * included with each copy of this software, whether used in part or whole,
 * at all times.
 *******************************************************************************
 */

/*******************************************************************************
 * Include files
 ******************************************************************************/
#include "basic.h"
#include "hc32_system.h"
#include "flash.h"

/**
 * @addtogroup HC32_Boot
 * @{
 */

/**
 * @defgroup BASIC BASIC
 * @{
 */

/*******************************************************************************
 * Local type definitions ('typedef')
 ******************************************************************************/

/*******************************************************************************
 * Local pre-processor symbols/macros ('#define')
 ******************************************************************************/
/**
 * @defgroup Basic_Local_Macros Basic Local Macros
 * @{
 */

/* CLK, EFM register bit definition */
#if defined(HC32F460)
    #define CMU_OSCSTBSR_HRCSTBF        (0x01U)
    #define CMU_OSCSTBSR_XTALSTBF       (0x08U)
    #define CMU_OSCSTBSR_MPLLSTBF       (0x20U)
    #define CMU_OSCSTBSR_UPLLSTBF       (0x40U)

    #define CMU_XTALCR_XTALSTP          (0x01U)
    #define CMU_HRCCR_HRCSTP            (0x01U)
    #define CMU_MRCCR_MRCSTP            (0x01U)
    #define CMU_PLLCR_MPLLOFF           (0x01U)

    #define CMU_CKSWR_CKSW_POS          (0x00U)
    #define CMU_CKSWR_CKSW              (0x07U)

    #define EFM_FRMC_FLWT_POS           (4U)
    #define EFM_FRMC_FLWT               (0x000000F0UL)

    #define PORT_PCCR_RDWT_POS          (14U)
    #define PORT_PCCR_RDWT              (0xC000U)
#endif

/* System clock configuration values */
#if defined(HC32F460)
    #define CLK_STABLE_TIME             (0x20000UL)
    #define CLK_FREQUENCY               (168000000UL)

    /* Hclk and Pclk0 div1; Exclk, Pclk1 and Pclk4 div2; Pclk2 and Pclk3 div4 */
    #define CLK_SCFGR_DIV               (0x00112210UL)
    #define SRAM_WAIT_CYCLE             (0x11001111UL)
    #if (SYSTEM_CLOCK_SOURCE == CLK_SOURCE_XTAL)
        #define CLK_XTAL_CONFIG         (0xA0U)
        /* XTAL = 8M, pllm=1, plln=42, pllp=pllq=pllr=2 */
        #define CLK_MPLL_CONFIG         (0x11102900UL)
    #else
        /* HRC = 16M, pllm=2, plln=42, pllp=pllq=pllr=2 */
        #define CLK_MPLL_CONFIG         (0x11102981UL)
    #endif
#elif defined(HC32F120) || defined(HC32M120) || defined(HC32F160)
    #if (SYSTEM_CLOCK_SOURCE == CLK_SOURCE_XTAL)
        #define CLK_STABLE_TIME         (0x10000UL)
    #endif
#elif defined(HC32F4A0)
    #define CLK_STABLE_TIME             (0x30000UL)
    #define CLK_FREQUENCY               (240000000UL)

    /* Hclk and Pclk0 div1; Exclk, Pclk1 and Pclk4 div2; Pclk2 and Pclk3 div4 */
    #define CLK_SCFGR_DIV               (0x00112210UL)
    #define SRAM_WAIT_CYCLE             (0x11001111UL)
    #if (SYSTEM_CLOCK_SOURCE == CLK_SOURCE_XTAL)
        /* XTAL = 8M, pllm=1, plln=120, pllp=pllq=pllr=4 */
        #define CLK_PLLH_CONFIG         (0x33307700UL)
    #else
        /* HRC = 16M, pllm=2, plln=120, pllp=pllq=pllr=4 */
        #define CLK_PLLH_CONFIG         (0x33307781UL)
    #endif
#elif defined(HC32M423)
    #define CLK_STABLE_TIME             (0x20000UL)
    #define CLK_FREQUENCY               (80000000UL)

    #if (SYSTEM_CLOCK_SOURCE == CLK_SOURCE_XTAL)
        /* XTAL = 8M, pllm=1, plln=20, pllp=2 */
        #define CLK_MPLL_CONFIG         (0x10001300UL)
    #else
        /* HRC = 48M, pllm=6, plln=20, pllp=2 */
        #define CLK_MPLL_CONFIG         (0x10001385UL)
    #endif
#endif

/**
 * @}
 */

/*******************************************************************************
 * Global variable definitions (declared in header file with 'extern')
 ******************************************************************************/
static uint32_t u32SystemClock;

/*******************************************************************************
 * Local function prototypes ('static')
 ******************************************************************************/

/*******************************************************************************
 * Local variable definitions ('static')
 ******************************************************************************/
__IO static uint32_t u32TickCount = 0UL;

/*******************************************************************************
 * Function implementation - global ('extern') and local ('static')
 ******************************************************************************/
/**
 * @defgroup Basic_Global_Functions Basic Global Functions
 * @{
 */

/**
 * @brief  System clock Initialize.
 * @param  None
 * @retval None
 */
void SystemClock_Init(void)
{
#if !((defined(HC32F120) || defined(HC32M120) || defined(HC32F160)) && (CLK_SOURCE_HRC == SYSTEM_CLOCK_SOURCE))
    uint8_t u8ClkStb;
    uint32_t u32Timeout = 0UL;
#endif

#if defined(HC32F460)
    uint32_t u32Temp;

    /* Set system clock division */
    WRITE_REG(M4_SYSREG->CMU_SCFGR, CLK_SCFGR_DIV);
    #if (SYSTEM_CLOCK_SOURCE == CLK_SOURCE_XTAL)
        /* Enable XTAL */
        WRITE_REG(M4_SYSREG->CMU_XTALCFGR, CLK_XTAL_CONFIG);
        WRITE_REG(M4_SYSREG->CMU_XTALCR, 0U);
        u32Temp = CMU_OSCSTBSR_XTALSTBF;
    #else
        /* Enable HRC */
        WRITE_REG(M4_SYSREG->CMU_HRCCR, 0U);
        u32Temp = CMU_OSCSTBSR_HRCSTBF;
    #endif
    do
    {
        u8ClkStb = READ_BIT(M4_SYSREG->CMU_OSCSTBSR, u32Temp);
        u32Timeout++;
    } while ((0U == u8ClkStb) && (u32Timeout < CLK_STABLE_TIME));

    /* Enable MPLL */
    u32Timeout = 0UL;
    WRITE_REG(M4_SYSREG->CMU_PLLCFGR, CLK_MPLL_CONFIG);
    WRITE_REG(M4_SYSREG->CMU_PLLCR, 0U);
    do
    {
        u8ClkStb = READ_BIT(M4_SYSREG->CMU_OSCSTBSR, CMU_OSCSTBSR_MPLLSTBF);
        u32Timeout++;
    } while ((0U == u8ClkStb) && (u32Timeout < CLK_STABLE_TIME));

    /* Set SRAM wait cycle: SRAM_H=1 cycle, SRAM_1_2_3_Ret=2 cycles */
    WRITE_REG(M4_SRAMC->WTCR, SRAM_WAIT_CYCLE);
    /* Set flash wait cycle: 4 cycles */
    MODIFY_REG(M4_EFM->FRMC, EFM_FRMC_FLWT, (0x04UL << EFM_FRMC_FLWT_POS));
    /* Set GPIO wait cycle: 3 cycles */
    MODIFY_REG(M4_PORT->PCCR, PORT_PCCR_RDWT, (0x03UL << PORT_PCCR_RDWT_POS));

    /* Switch system clock source to MPLL */
    u32Timeout = 0UL;
    WRITE_REG(M4_SYSREG->CMU_CKSWR, (0x05U << CMU_CKSWR_CKSW_POS));
    do
    {
        u32Timeout++;
    } while (u32Timeout < CLK_STABLE_TIME);
    /* Set system clock to 168MHz */
    u32SystemClock = CLK_FREQUENCY;
#elif defined(HC32F120) || defined(HC32M120)
    #if (SYSTEM_CLOCK_SOURCE == CLK_SOURCE_XTAL)
        /* Enable XTAL */
        WRITE_REG(M0P_CMU->XTALCR, 0U);
        do
        {
            u8ClkStb = READ_BIT(M0P_CMU->OSCSTBSR, CMU_OSCSTBSR_XTALSTBF);
            u32Timeout++;
        } while ((0U == u8ClkStb) && (u32Timeout < CLK_STABLE_TIME));
        /* Switch system clock source to XTAL */
        WRITE_REG(M0P_CMU->CKSWR, (0x01U << CMU_CKSWR_CKSW_POS));
        u32SystemClock = XTAL_VALUE;
    #else
        /* Set flash wait cycle */
        SET_BIT(M0P_EFM->FRMC, EFM_FRMC_FLWT);
        u32SystemClock = HRC_VALUE;
    #endif
#elif defined(HC32F160)
    #if (SYSTEM_CLOCK_SOURCE == CLK_SOURCE_XTAL)
        /* Enable XTAL */
        WRITE_REG(CM_CMU->XTALCR, 0U);
        do
        {
            u8ClkStb = READ_BIT(CM_CMU->OSCSTBSR, CMU_OSCSTBSR_XTALSTBF);
            u32Timeout++;
        } while ((0U == u8ClkStb) && (u32Timeout < CLK_STABLE_TIME));
        /* Switch system clock source to XTAL */
        WRITE_REG(CM_CMU->CKSWR, (0x01U << CMU_CKSWR_CKSW_POS));
        u32SystemClock = XTAL_VALUE;
    #else
        /* Set flash wait cycle */
        SET_BIT(CM_EFM->FRMC, EFM_FRMC_FLWT_1);
        u32SystemClock = HRC_VALUE;
    #endif
#elif defined(HC32F4A0)
    /* Set system clock division */
    WRITE_REG(M4_CMU->SCFGR, CLK_SCFGR_DIV);
    /* Enable PLLH */
    WRITE_REG(M4_CMU->PLLHCFGR, CLK_PLLH_CONFIG);
    WRITE_REG(M4_CMU->PLLHCR, 0U);
    do
    {
        u8ClkStb = READ_BIT(M4_CMU->OSCSTBSR, CMU_OSCSTBSR_PLLHSTBF);
        u32Timeout++;
    } while ((0U == u8ClkStb) && (u32Timeout < CLK_STABLE_TIME));

    /* Set SRAM wait cycle: SRAM_H=1 cycle, SRAM_1_2_3_4_B=2 cycles */
    WRITE_REG(M4_SRAMC->WTCR, SRAM_WAIT_CYCLE);
    /* Set flash wait cycle: 5 cycles */
    MODIFY_REG(M4_EFM->FRMC, EFM_FRMC_FLWT, (0x05UL << EFM_FRMC_FLWT_POS));
    /* Set GPIO wait cycle: 4 cycles */
    MODIFY_REG(M4_GPIO->PCCR, GPIO_PCCR_RDWT, (0x04UL << GPIO_PCCR_RDWT_POS));

    /* Switch system clock source to PLLH */
    u32Timeout = 0UL;
    WRITE_REG(M4_CMU->CKSWR, 0x05U);
    do
    {
        u32Timeout++;
    } while (u32Timeout < CLK_STABLE_TIME);
    /* Set system clock to 240MHz */
    u32SystemClock = CLK_FREQUENCY;
#elif defined(HC32M423)
    #if (SYSTEM_CLOCK_SOURCE == CLK_SOURCE_XTAL)
        /* Enable XTAL */
        WRITE_REG(CM_CMU->XTALCR, 0U);
        do
        {
            u8ClkStb = READ_BIT(CM_CMU->OSCSTBSR, CMU_OSCSTBSR_XTALSTBF);
            u32Timeout++;
        } while ((0U == u8ClkStb) && (u32Timeout < CLK_STABLE_TIME));
    #endif

    /* Enable MPLL */
    u32Timeout = 0UL;
    WRITE_REG(CM_CMU->PLLCFGR, CLK_MPLL_CONFIG);
    WRITE_REG(CM_CMU->PLLCR, 0U);
    do
    {
        u8ClkStb = READ_BIT(CM_CMU->OSCSTBSR, CMU_OSCSTBSR_PLLSTBF);
        u32Timeout++;
    } while ((0U == u8ClkStb) && (u32Timeout < CLK_STABLE_TIME));

    /* Set flash wait cycle: 3 cycles */
    MODIFY_REG(CM_EFM->FRMC, EFM_FRMC_FLWT, (0x03UL << EFM_FRMC_FLWT_POS));
    /* Set GPIO wait cycle: 3 cycles */
    MODIFY_REG(CM_GPIO->PCCR, GPIO_PCCR_RDWT, (0x03UL << GPIO_PCCR_RDWT_POS));
    /* Wait stable after open fcg */
    CLEAR_BIT(CM_PWC->PWRC, PWC_PWRC_DVS);
    u32Timeout = 0UL;
    do
    {
        u32Timeout++;
    } while(u32Timeout < CLK_STABLE_TIME);

    /* Switch system clock source to MPLL */
    u32Timeout = 0UL;
    WRITE_REG(CM_CMU->CKSWR, 0x05U);
    do
    {
        u32Timeout++;
    } while (u32Timeout < CLK_STABLE_TIME);
    /* Set system clock to 80MHz */
    u32SystemClock = CLK_FREQUENCY;
#endif
}

/**
 * @brief  System clock De-Initialize.
 * @param  None
 * @retval None
 */
void SystemClock_DeInit(void)
{
#if defined(HC32F460) || defined(HC32F4A0) || defined(HC32M423)
    uint32_t u32Timeout;
#endif

#if defined(HC32F460)
    /* Switch system clock source to MRC */
    WRITE_REG(M4_SYSREG->CMU_CKSWR, (0x01U << CMU_CKSWR_CKSW_POS));
    u32Timeout = CLK_STABLE_TIME;
    while ((u32Timeout--) > 0UL)
    {
    }
    WRITE_REG(M4_SYSREG->CMU_SCFGR, 0UL);

    #if (SYSTEM_CLOCK_SOURCE == CLK_SOURCE_XTAL)
        /* Disable XTAL */
        WRITE_REG(M4_SYSREG->CMU_XTALCR, CMU_XTALCR_XTALSTP);
        WRITE_REG(M4_SYSREG->CMU_XTALCFGR, 0U);
    #else
        /* Disable HRC */
        WRITE_REG(M4_SYSREG->CMU_HRCCR, CMU_HRCCR_HRCSTP);
    #endif
    /* Disable MPLL */
    WRITE_REG(M4_SYSREG->CMU_PLLCR,   CMU_PLLCR_MPLLOFF);
    WRITE_REG(M4_SYSREG->CMU_PLLCFGR, 0x11101300UL);

    /* Set SRAM wait cycle */
    WRITE_REG(M4_SRAMC->WTCR, 0x00001100UL);
    /* Set flash wait cycle */
    MODIFY_REG(M4_EFM->FRMC, EFM_FRMC_FLWT, 0UL);
    /* Set GPIO wait cycle */
    WRITE_REG(M4_PORT->PCCR, 0x4000U);
#elif defined(HC32F120) || defined(HC32M120)
    #if (SYSTEM_CLOCK_SOURCE == CLK_SOURCE_XTAL)
        /* Disable XTAL */
        WRITE_REG(M0P_CMU->XTALCR,   CMU_XTALCR_XTALSTP);
        WRITE_REG(M0P_CMU->XTALCFGR, 0x80U);
        /* Reset the system source */
        WRITE_REG(M0P_CMU->CKSWR, 0U);
    #endif
#elif defined(HC32F160)
    #if (SYSTEM_CLOCK_SOURCE == CLK_SOURCE_XTAL)
        /* Disable XTAL */
        WRITE_REG(CM_CMU->XTALCR,   CMU_XTALCR_XTALSTP);
        WRITE_REG(CM_CMU->XTALCFGR, 0x80U);
        /* Reset the system source */
        WRITE_REG(CM_CMU->CKSWR, 0U);
    #endif
#elif defined(HC32F4A0)
    /* Switch system clock source to MRC */
    WRITE_REG(M4_CMU->CKSWR, 0x01U);
    u32Timeout = CLK_STABLE_TIME;
    while ((u32Timeout--) > 0UL)
    {
    }
    WRITE_REG(M4_CMU->SCFGR, 0UL);

    #if (SYSTEM_CLOCK_SOURCE == CLK_SOURCE_XTAL)
        /* Disable XTAL */
        WRITE_REG(M4_CMU->XTALCR, CMU_XTALCR_XTALSTP);
    #else
        /* Disable HRC */
        WRITE_REG(M4_CMU->HRCCR, CMU_HRCCR_HRCSTP);
    #endif
    /* Disable PLLH */
    WRITE_REG(M4_CMU->PLLHCR,   CMU_PLLHCR_PLLHOFF);
    WRITE_REG(M4_CMU->PLLHCFGR, 0x11101300UL);

    /* Set SRAM wait cycle */
    WRITE_REG(M4_SRAMC->WTCR, 0UL);
    /* Set flash wait cycle */
    MODIFY_REG(M4_EFM->FRMC, EFM_FRMC_FLWT, 0UL);
    /* Set GPIO wait cycle */
    WRITE_REG(M4_GPIO->PCCR, 0x1000U);
#elif defined(HC32M423)
    /* Switch system clock source to MRC */
    WRITE_REG(CM_CMU->CKSWR, 0x01U);
    u32Timeout = CLK_STABLE_TIME;
    while ((u32Timeout--) > 0UL)
    {
    }

    #if (SYSTEM_CLOCK_SOURCE == CLK_SOURCE_XTAL)
        /* Disable XTAL */
        WRITE_REG(CM_CMU->XTALCR, CMU_XTALCR_XTALSTP);
    #endif
    /* Disable MPLL */
    WRITE_REG(CM_CMU->PLLCR,   CMU_PLLCR_PLLOFF);
    WRITE_REG(CM_CMU->PLLCFGR, 0UL);

    /* Set flash wait cycle */
    MODIFY_REG(CM_EFM->FRMC, EFM_FRMC_FLWT, 0UL);
    /* Set GPIO wait cycle */
    WRITE_REG(CM_GPIO->PCCR, 0x4000U);
    SET_BIT(CM_PWC->PWRC, PWC_PWRC_DVS);
    /* Wait stable after open fcg */
    u32Timeout = 0UL;
    do
    {
        u32Timeout++;
    } while(u32Timeout < CLK_STABLE_TIME);
#endif
}

/**
 * @brief  Systick Initialize
 * @param  None
 * @retval None
 */
void SysTick_Init(void)
{
    /* Configure the SysTick interrupt */
    (void)SysTick_Config(u32SystemClock / 1000U);
}

/**
 * @brief  Systick De-Initialize
 * @param  None
 * @retval None
 */
void SysTick_DeInit(void)
{
    /* Disable SysTick IRQ and SysTick Timer */
    SysTick->CTRL  = 0UL;
    SysTick->LOAD  = 0UL;
    SysTick->VAL   = 0UL;
}

/**
 * @brief  Provides a tick value in millisecond.
 * @param  None
 * @retval Tick value
 */
uint32_t SysTick_GetTick(void)
{
    return u32TickCount;
}

/**
 * @brief  SysTick IRQ handler
 * @param  None
 * @retval None
 */
void SysTick_Handler(void)
{
    u32TickCount++;
}

/**
 * @brief This function provides minimum delay (in milliseconds).
 * @param [in] u32DelayMs               Delay specifies the delay time.
 * @retval None
 */
void SysTick_Delay(uint32_t u32DelayMs)
{
    uint32_t u32TickStart;
    uint32_t u32NewTick;
    uint32_t u32DelayVal;

    u32TickStart = SysTick_GetTick();
    do 
    {
        u32NewTick  = SysTick_GetTick();
        u32DelayVal = (u32NewTick > u32TickStart) ? (u32NewTick - u32TickStart) : (TICK_RELOAD_VALUE - u32TickStart + 1U + u32NewTick);
    } while(u32DelayVal < u32DelayMs);
}

/**
 * @brief  LED Initialize
 * @param  None
 * @retval None
 */
void LED_Init(void)
{
    /* Enable GPIO output */
#if defined(HC32F4A0)
    SET_BIT(LED_G1_EN_PORT, LED_G1_PIN);
    SET_BIT(LED_G2_EN_PORT, LED_G2_PIN);
    /* Turn Off LED */
    LED_OFF(LED_G1_PORT, LED_G1_PIN);
    LED_OFF(LED_G2_PORT, LED_G2_PIN);
#else
    SET_BIT(LED_R_EN_PORT, LED_R_PIN);
    SET_BIT(LED_B_EN_PORT, LED_B_PIN);
    /* Turn Off LED */
    LED_OFF(LED_R_PORT, LED_R_PIN);
    LED_OFF(LED_B_PORT, LED_B_PIN);
#endif
}

/**
 * @brief  LED De-Initialize
 * @param  None
 * @retval None
 */
void LED_DeInit(void)
{
    /* Disable GPIO output */
#if defined(HC32F4A0)
    CLEAR_BIT(LED_G1_EN_PORT, LED_G1_PIN);
    CLEAR_BIT(LED_G2_EN_PORT, LED_G2_PIN);
#else
    CLEAR_BIT(LED_R_EN_PORT, LED_R_PIN);
    CLEAR_BIT(LED_B_EN_PORT, LED_B_PIN);
#endif
}

/**
 * @brief  CRC Initialize
 * @param  None
 * @retval None
 */
void CRC_Init(void)
{
    /* Enable CRC Clock */
#if defined(HC32F460)
    CLEAR_BIT(M4_MSTP->FCG0, MSTP_FCG0_CRC);
#elif defined(HC32F120) || defined(HC32M120)
    CLEAR_BIT(M0P_CMU->FCG, CMU_FCG_CRC);
#elif defined(HC32F4A0)
    CLEAR_BIT(M4_PWC->FCG0, PWC_FCG0_CRC);
#elif defined(HC32M423) || defined(HC32F160)
    CLEAR_BIT(CM_CMU->FCG, CMU_FCG_CRC);
#endif
}

/**
 * @brief  CRC De-Initialize
 * @param  None
 * @retval None
 */
void CRC_DeInit(void)
{
    /* Disable CRC Clock */
#if defined(HC32F460)
    SET_BIT(M4_MSTP->FCG0, MSTP_FCG0_CRC);
#elif defined(HC32F120) || defined(HC32M120)
    SET_BIT(M0P_CMU->FCG, CMU_FCG_CRC);
#elif defined(HC32F4A0)
    SET_BIT(M4_PWC->FCG0, PWC_FCG0_CRC);
#elif defined(HC32M423) || defined(HC32F160)
    SET_BIT(CM_CMU->FCG, CMU_FCG_CRC);
#endif
}

/**
 * @brief  Calculate CRC16 for Packet
 * @param  [in] pu8Data                 Pointer to the buffer which the data to be calculate.
 * @param  [in] u32Size                 Buffer length.
 * @retval uint16_t                     Calculate result
 */
uint16_t Calculate_CRC16(const uint8_t* pu8Data, uint32_t u32Size)
{
    uint32_t u32Cnt;
    uint16_t u16CrcResult = 0xA28CU;

#if defined(HC32F460)
    CLEAR_BIT(CRC_BASE->CR, CRC_CR_SEL);
#else
    CLEAR_BIT(CRC_BASE->CR, CRC_CR_CR);
#endif
    WRITE_REG(CRC_BASE->RESLT, u16CrcResult);
    /* Loading Data */
    for (u32Cnt=0UL; u32Cnt<u32Size; u32Cnt++)
    {
        WRITE_REG(*((__IO uint8_t *)&CRC_BASE->DAT0), pu8Data[u32Cnt]);
    }
    u16CrcResult = (uint16_t)READ_REG(CRC_BASE->RESLT);

    return u16CrcResult;
}

/**
 * @brief  Get Flash CRC check value
 * @param  [in] u32Addr                 Flash address
 * @param  [in] u32ByteLength           Data length
 * @param  [out] u16CrcVal              Pointer to the crc value
 * @retval An en_result_t enumeration value:
 *           - Ok: Get crc value succeeded
 *           - ErrorInvalidParameter: The parameters is invalid
 */
en_result_t FLASH_GetCrcValue(uint32_t u32Addr, uint32_t u32ByteLength, uint16_t *u16CrcVal)
{
    uint32_t u32Cnt;
    uint16_t u16CrcResult = 0xA28CU;
    __IO uint8_t *pu8FlashAddr;

    if (((u32Addr + u32ByteLength) > (FLASH_BASE + FLASH_SIZE)) ||
        (0UL == u32ByteLength))
    {
        return ErrorInvalidParameter;
    }

    pu8FlashAddr = (__IO uint8_t*)u32Addr;
#if defined(HC32F460)
    CLEAR_BIT(CRC_BASE->CR, CRC_CR_SEL);
#else
    CLEAR_BIT(CRC_BASE->CR, CRC_CR_CR);
#endif
    WRITE_REG(CRC_BASE->RESLT, u16CrcResult);
    /* Loading Data */
    for (u32Cnt=0UL; u32Cnt<u32ByteLength; u32Cnt++)
    {
        WRITE_REG(*((__IO uint8_t *)&CRC_BASE->DAT0), pu8FlashAddr[u32Cnt]);
    }
    *u16CrcVal = (uint16_t)READ_REG(CRC_BASE->RESLT);

    return Ok;
}

/**
 * @}
 */

/**
 * @}
 */

/**
* @}
*/

/******************************************************************************
 * EOF (not truncated)
 *****************************************************************************/
